import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.Charset;
import java.util.LinkedList;
import java.util.List;

public class CountChineseChar
{
    class FileOrDir
    {
        boolean         dir              = false;
        int             numOfChineseWord = 0;
        int             numOfEnglishWord = 0;
        List<FileOrDir> content;
        File            file;

        FileOrDir(File file) throws IOException
        {
            this.file = file;
            if (file.isDirectory())
            {
                dir = true;
                content = new LinkedList<>();
                for (File each : file.listFiles())
                {
                    FileOrDir fileOrDir = new FileOrDir(each);
                    if (fileOrDir.numOfChineseWord != 0)
                    {
                        content.add(fileOrDir);
                        numOfChineseWord += fileOrDir.numOfChineseWord;
                        numOfEnglishWord += fileOrDir.numOfEnglishWord;
                    }
                }
            }
            else
            {
                if (file.getName().endsWith("md") == false)
                {
                    return;
                }
                FileChannel      channel    = new RandomAccessFile(file, "r").getChannel();
                MappedByteBuffer byteBuffer = channel.map(FileChannel.MapMode.READ_ONLY, 0, channel.size());
                byte[]           array      = new byte[byteBuffer.capacity()];
                byteBuffer.get(array);
                String  content       = new String(array, Charset.forName("utf8"));
                boolean inEnglishWord = false;
                for (char c : content.toCharArray())
                {
                    if (isCHinese(c))
                    {
                        numOfChineseWord++;
                        if (inEnglishWord)
                        {
                            inEnglishWord = false;
                            numOfEnglishWord++;
                        }
                    }
                    else if (isEnglishChar(c, inEnglishWord))
                    {
                        if (inEnglishWord == false)
                        {
                            inEnglishWord = true;
                        }
                    }
                    else
                    {
                        if (inEnglishWord)
                        {
                            inEnglishWord = false;
                            numOfEnglishWord++;
                        }
                    }
                }
                channel.close();
            }
        }

        boolean isEnglishChar(char c, boolean inEnglishWord)
        {
            if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))
            {
                return true;
            }
            else if (c >= '0' && c <= '9' && inEnglishWord)
            {
                return true;
            }
            else if ("+=_-[]{}<>".contains(String.valueOf(c)) && inEnglishWord)
            {
                return true;
            }
            else
            {
                return false;
            }
        }

        public void log()
        {
            if (dir)
            {
                System.out.println("文件夹：《" + file.getAbsolutePath() + "》下所有文件的总汉字数：" + numOfChineseWord + "总英文数：" + numOfEnglishWord + "，该文件夹下文件有：");
                for (FileOrDir each : content)
                {
                    each.log();
                }
            }
            else
            {
                System.out.println("文件：《" + file.getAbsolutePath() + "》的汉字个数是：" + numOfChineseWord + "，英文单词数：" + numOfEnglishWord);
            }
        }

        public String markdown()
        {
            StringBuilder builder = new StringBuilder();
            markdown(builder, 0);
            return builder.toString();
        }

        private void markdown(StringBuilder builder, int level)
        {
            switch (level)
            {
                case 0:
                    builder.append("# ");
                    break;
                case 1:
                    builder.append("## ");
                    break;
                case 2:
                    builder.append("### ");
                    break;
                default:
                    for (int i = 3; i < level; i++)
                    {
                        builder.append("\t");
                    }
                    builder.append("- ");
                    break;
            }
            builder.append(file.getName()).append("(中文:").append(numOfChineseWord).append(",英文:").append(numOfEnglishWord).append(")");
            builder.append("\r\n");
            if (dir)
            {
                for (FileOrDir each : content)
                {
                    each.markdown(builder, level + 1);
                }
            }
        }
    }

    FileOrDir root;

    public CountChineseChar(String path) throws IOException
    {
        root = new FileOrDir(new File(path));
    }

    public void log()
    {
        root.log();
    }

    public String toString()
    {
        return root.markdown();
    }

    public static boolean isCHinese(char c)
    {
        Character.UnicodeBlock ub = Character.UnicodeBlock.of(c);
        if (ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS //
                || ub == Character.UnicodeBlock.CJK_COMPATIBILITY_IDEOGRAPHS//
                || ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A //
            //   || ub == Character.UnicodeBlock.GENERAL_PUNCTUATION  // GENERAL_PUNCTUATION 判断中文的“号
            // || ub == Character.UnicodeBlock.CJK_SYMBOLS_AND_PUNCTUATION     // CJK_SYMBOLS_AND_PUNCTUATION 判断中文的。号
            // || ub == Character.UnicodeBlock.HALFWIDTH_AND_FULLWIDTH_FORMS    // HALFWIDTH_AND_FULLWIDTH_FORMS 判断中文的，号
        )
        {
            return true;
        }
        return false;
    }

    public static void main(String[] args) throws IOException
    {
        System.out.println(new CountChineseChar("D:\\笔记\\我的笔记\\源码阅读\\RocketMq学习笔记"));
    }
}
